﻿// ***********************************************************************
// Assembly         : OpenAuth.WebApi
// Author           : yubaolee
// Created          : 07-11-2016
//
// Last Modified By : yubaolee
// Last Modified On : 07-11-2016
// Contact :
// File: CheckController.cs
// 登录相关的操作
// ***********************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using Infrastructure;
using Infrastructure.Cache;
using Infrastructure.Helpers;
using Infrastructure.Helpers.RSAHelper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using MySqlX.XDevAPI.Common;
using OpenAuth.App;
using OpenAuth.App.Interface;
using OpenAuth.App.Response;
using OpenAuth.App.SSO;
using OpenAuth.Repository.Domain;
using StackExchange.Profiling;

namespace OpenAuth.WebApi.Controllers
{
    /// <inheritdoc />
    /// <summary>
    /// 登录及与登录信息获取相关的接口
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    [ApiExplorerSettings(GroupName = "登录验证_Check")]
    public class CheckController : ControllerBase
    {
        private readonly IAuth _authUtil;
        private ILogger _logger;
        private AuthStrategyContext _authStrategyContext;
        private ICacheContext _cacheContext;

        public CheckController(IAuth authUtil, ICacheContext cacheContext, ILogger<CheckController> logger)
        {
            _authUtil = authUtil;
            _logger = logger;
            _cacheContext = cacheContext;
            _authStrategyContext = _authUtil.GetCurrentUser();
        }

        /// <summary>
        /// 获取登录用户资料
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public Response<UserView> GetUserProfile()
        {
            var resp = new Response<UserView>();
            try
            {

                resp.Result = _authStrategyContext.User.MapTo<UserView>();
            }
            catch (Exception e)
            {
                resp.Code = 500;
                resp.Message = e.Message;
            }

            return resp;
        }

        /// <summary>
        /// 检验token是否有效
        /// </summary>
        /// <param name="token">The token.</param>
        /// <param name="requestid">备用参数.</param>
        [HttpGet]

        public Response<bool> GetStatus()
        {
            var result = new Response<bool>();
            try
            {
                result.Result = _authUtil.CheckLogin();
            }
            catch (Exception ex)
            {
                result.Code = Define.INVALID_TOKEN;
                result.Message = ex.Message;
            }

            return result;
        }
        /// <summary>
        /// 获取登录用户的所有可访问的角色
        /// </summary>
        [HttpGet]
        public Response<List<Role>> GetRoles()
        {
            var result = new Response<List<Role>>();
            try
            {
                result.Result = _authStrategyContext.Roles;
            }
            catch (CommonException ex)
            {
                if (ex.Code == Define.INVALID_TOKEN)
                {
                    result.Code = ex.Code;
                    result.Message = ex.Message;
                }
                else
                {
                    result.Code = 500;
                    result.Message = ex.InnerException != null
                        ? "OpenAuth.WebAPI数据库访问失败:" + ex.InnerException.Message
                        : "OpenAuth.WebAPI数据库访问失败:" + ex.Message;
                }

            }

            return result;
        }

        /// <summary>
        /// 获取当前登录用户可访问的字段
        /// </summary>
        /// <param name="moduleCode">模块的Code，如Category</param>
        /// <returns></returns>
        [HttpGet]
        public Response<List<BuilderTableColumn>> GetProperties(string moduleCode)
        {
            var result = new Response<List<BuilderTableColumn>>();
            try
            {
                result.Result = _authStrategyContext.GetTableColumns(moduleCode);
            }
            catch (Exception ex)
            {
                result.Code = 500;
                result.Message = ex.InnerException?.Message ?? ex.Message;
            }

            return result;
        }
        /// <summary>
        /// 获取登录用户的所有可访问的组织信息
        /// </summary>
        [HttpGet]
        public Response<List<SysOrg>> GetOrgs()
        {
            var result = new Response<List<SysOrg>>();
            try
            {
                result.Result = _authStrategyContext.Orgs;
            }
            catch (CommonException ex)
            {
                if (ex.Code == Define.INVALID_TOKEN)
                {
                    result.Code = ex.Code;
                    result.Message = ex.Message;
                }
                else
                {
                    result.Code = 500;
                    result.Message = ex.InnerException != null
                        ? "OpenAuth.WebAPI数据库访问失败:" + ex.InnerException.Message
                        : "OpenAuth.WebAPI数据库访问失败:" + ex.Message;
                }

            }

            return result;
        }

        /// <summary>
        /// 加载机构的全部下级机构
        /// </summary>
        /// <param name="orgId">机构ID</param>
        /// <returns></returns>
        [HttpGet]
        public TableData GetSubOrgs(string orgId)
        {
            string cascadeId = ".0.";
            if (!string.IsNullOrEmpty(orgId))
            {
                var org = _authStrategyContext.Orgs.SingleOrDefault(u => u.Id == orgId);
                if (org == null)
                {
                    return new TableData
                    {
                        msg = "未找到指定的节点",
                        code = 500,
                    };
                }
                cascadeId = org.CascadeId;
            }

            var query = _authStrategyContext.Orgs
                .Where(u => u.CascadeId.Contains(cascadeId))
                .OrderBy(u => u.CascadeId);

            return new TableData
            {
                data = query.ToList(),
                count = query.Count(),
            };
        }

        /// <summary>
        /// 获取登录用户的所有可访问的模块及菜单，以列表形式返回结果
        /// </summary>
        [HttpGet]
        public Response<List<ModuleView>> GetModules()
        {
            var result = new Response<List<ModuleView>>();
            try
            {
                result.Result = _authStrategyContext.Modules;
            }
            catch (CommonException ex)
            {
                if (ex.Code == Define.INVALID_TOKEN)
                {
                    result.Code = ex.Code;
                    result.Message = ex.Message;
                }
                else
                {
                    result.Code = 500;
                    result.Message = ex.InnerException != null
                        ? "OpenAuth.WebAPI数据库访问失败:" + ex.InnerException.Message
                        : "OpenAuth.WebAPI数据库访问失败:" + ex.Message;
                }

            }

            return result;
        }

        /// <summary>
        /// 获取登录用户的所有可访问的模块及菜单，以树状结构返回
        /// </summary>
        [HttpGet]
        public Response<IEnumerable<TreeItem<ModuleView>>> GetModulesTree()
        {
            var result = new Response<IEnumerable<TreeItem<ModuleView>>>();
            try
            {
                result.Result = _authStrategyContext.Modules.GenerateTree(u => u.Id, u => u.ParentId);
            }
            catch (CommonException ex)
            {
                if (ex.Code == Define.INVALID_TOKEN)
                {
                    result.Code = ex.Code;
                    result.Message = ex.Message;
                }
                else
                {
                    result.Code = 500;
                    result.Message = ex.InnerException != null
                        ? "OpenAuth.WebAPI数据库访问失败:" + ex.InnerException.Message
                        : "OpenAuth.WebAPI数据库访问失败:" + ex.Message;
                }

            }

            return result;
        }

        /// <summary>
        /// 获取登录用户的所有可访问的资源
        /// </summary>
        [HttpGet]
        public Response<List<Resource>> GetResources()
        {
            var result = new Response<List<Resource>>();
            try
            {
                result.Result = _authUtil.GetCurrentUser().Resources;
            }
            catch (CommonException ex)
            {
                if (ex.Code == Define.INVALID_TOKEN)
                {
                    result.Code = ex.Code;
                    result.Message = ex.Message;
                }
                else
                {
                    result.Code = 500;
                    result.Message = ex.InnerException != null
                        ? "OpenAuth.WebAPI数据库访问失败:" + ex.InnerException.Message
                        : "OpenAuth.WebAPI数据库访问失败:" + ex.Message;
                }

            }

            return result;
        }

        /// <summary>
        /// 根据token获取用户名称
        /// </summary>
        [HttpGet]
        public Response<string> GetUserName()
        {
            var result = new Response<string>();
            try
            {

                result.Result = _authUtil.GetCurrentUser().User.Account;
            }
            catch (CommonException ex)
            {
                if (ex.Code == Define.INVALID_TOKEN)
                {
                    result.Code = ex.Code;
                    result.Message = ex.Message;
                }
                else
                {
                    result.Code = 500;
                    result.Message = ex.InnerException != null
                        ? ex.InnerException.Message : ex.Message;
                }

            }

            return result;
        }

        /// <summary>
        /// 登录接口
        /// </summary>
        /// <param name="request">登录参数</param>
        /// <returns></returns>
        [HttpPost]
        [AllowAnonymous]
        public LoginResult Login(PassportLoginRequest request)
        {
            var result = new LoginResult();
            try
            {
                if (string.IsNullOrEmpty(request.Account))
                {
                    throw new Exception("登录名不能为空");
                }
                if (string.IsNullOrEmpty(request.Password))
                {
                    throw new Exception("密码不能为空");
                }
                if (string.IsNullOrEmpty(request.ranval))
                {
                    throw new Exception("验证码不能为空");
                }
                if (string.IsNullOrEmpty(request.verifycode))
                {
                    throw new Exception("请输入验证码");
                }

                request.Account = request.Account.Trim();
                request.Password = request.Password.Trim();
                request.verifycode = request.verifycode.Trim();


                var cache_ranval = _cacheContext.Get<string>(request.ranval);

                if (cache_ranval == null)
                {
                    throw new Exception("验证码未创建请刷新浏览器。");
                }

                if (request.verifycode.ToLower() != cache_ranval.ToLower())
                {
                    throw new Exception("验证码输入错误");
                }

                //替换验证码内容强制让验证码过期
                _cacheContext.Set(request.ranval, Guid.NewGuid().ToString("N"), DateTime.Now.AddSeconds(3));

                result = _authUtil.Login(request.AppKey, request.Account, request.Password);
            }
            catch (Exception ex)
            {
                result.Code = 500;
                result.Message = ex.Message;
            }

            return result;
        }



        /// <summary>
        /// 登录前获取RSA公钥
        /// </summary>
        /// <param name="request">登录参数</param>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        public Response<string> GetRSAPublicKey()
        {
            var result = new Response<string>();
            result.Result = RSAKey.PublicKey;
            return result;
        }

        /// <summary>
        /// 注销登录
        /// </summary>
        /// <param name="token"></param>
        /// <param name="requestid">备用参数.</param>
        [HttpPost]
        public Response<bool> Logout()
        {
            var resp = new Response<bool>();
            try
            {
                resp.Result = _authUtil.Logout();
            }
            catch (Exception e)
            {
                resp.Result = false;
                resp.Message = e.Message;
            }

            return resp;
        }



        /// <summary>
        /// 获取验证码
        /// </summary>
        /// <param name="orgId">机构ID</param>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        public Response<string> verify(string ranval)
        {

            var result = new Response<string>();
            try
            {

                if (string.IsNullOrEmpty(ranval))
                {
                    throw new Exception("缺少参数：ranval");
                }
                

                string code = GetRanCode(4);

                string base64 = GenerateCaptchaSvgBase64(code);

                _cacheContext.Set(ranval, code, DateTime.Now.AddMinutes(10));

                result.Result = base64;
                return result;

            }
            catch (Exception e)
            {
                result.Code = 500;
                result.Message = e.Message;

                return result;
            }
        }

        public static string GetRanCode(int length)
        {

            // 随机字符集
            string chars = "123456789";
            Random rand = new Random();

            // 生成验证码字符串
            string code = "";
            for (int i = 0; i < length; i++)
            {
                code += chars[rand.Next(chars.Length)];
            }

            return code;
        }

        /// <summary>
        /// 生成验证码图片并返回Base64
        /// </summary>
        /// <param name="length">验证码长度</param>
        /// <returns>验证码图片Base64字符串</returns>using SixLabors.ImageSharp;
        public string GenerateCaptchaSvgBase64(string code)
        {
            var rand = new Random();
            int width = code.Length * 25;
            int height = 40;

            var sb = new System.Text.StringBuilder();
            sb.Append($"<svg xmlns='http://www.w3.org/2000/svg' width='{width}' height='{height}'>");
            sb.Append("<rect width='100%' height='100%' fill='white'/>");

            // 干扰线
            for (int i = 0; i < 4; i++)
            {
                int x1 = rand.Next(width);
                int y1 = rand.Next(height);
                int x2 = rand.Next(width);
                int y2 = rand.Next(height);
                sb.Append($"<line x1='{x1}' y1='{y1}' x2='{x2}' y2='{y2}' stroke='lightgray'/>");
            }

            // 验证码字符
            for (int i = 0; i < code.Length; i++)
            {

                // 生成可识别的颜色
                int r = rand.Next(0, 2) == 0 ? rand.Next(0, 100) : rand.Next(155, 255);
                int g = rand.Next(0, 2) == 0 ? rand.Next(0, 100) : rand.Next(155, 255);
                int b = rand.Next(0, 2) == 0 ? rand.Next(0, 100) : rand.Next(155, 255);

                // 避免灰色，确保差异足够大
                while (Math.Abs(r - g) < 50 && Math.Abs(r - b) < 50 && Math.Abs(g - b) < 50)
                {
                    r = rand.Next(0, 2) == 0 ? rand.Next(0, 100) : rand.Next(155, 255);
                    g = rand.Next(0, 2) == 0 ? rand.Next(0, 100) : rand.Next(155, 255);
                    b = rand.Next(0, 2) == 0 ? rand.Next(0, 100) : rand.Next(155, 255);
                }

                string color = $"rgb({r},{g},{b})";


                int x = i * 20 + rand.Next(5);
                int y = rand.Next(20, 35);
                sb.Append($"<text x='{x}' y='{y}' fill='{color}' font-size='20' font-family='Arial' font-weight='bold'>{code[i]}</text>");
            }

            // 噪点（用小圆点代替）
            for (int i = 0; i < 100; i++)
            {
                int x = rand.Next(width);
                int y = rand.Next(height);
                sb.Append($"<circle cx='{x}' cy='{y}' r='1' fill='black'/>");
            }

            sb.Append("</svg>");

            string svg = sb.ToString();
            string base64 = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(svg));
            return $"data:image/svg+xml;base64,{base64}";
        }
    }
}